﻿using Org.LLRP.LTK.LLRPV1.Impinj;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace RFID
{
    public class TagManager
    {
        DeviceManager dm;
        public TagManager(ENUM_ImpinjInventorySearchType searchType, params string[] IpList)
        {
            dm = new DeviceManager(this, searchType, IpList);
        }

        List<Tag> tags = new List<Tag>();
        public List<Tag> Tags
        {
            get { return tags; }
            set { tags = value; }
        }

        Location GetLocation(int AntennaId)
        {
            Location result = Location.Inside;
            if (AntennaId == 1 || AntennaId == 3)
            {
                return Location.Inside;
            }
            else if (AntennaId == 2 || AntennaId == 4)
            {
                return Location.Outside;
            }

            return result;
        }

        public delegate void TagLocationChangedHandler(Tag tag);
        public event TagLocationChangedHandler TagLocationChanged;

        public delegate void TagReadHandler(Tag tag, double rssi);
        public event TagReadHandler TagRead;


        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            foreach (Tag tag in Tags)
            {
                sb.Append(tag.ToString() + Environment.NewLine);
            }
            return sb.ToString();
        }

        public void ProcessTag(int id, ushort antennaId, double rssi)
        {
            if (id == 0)
                return;
            //id = id - IdShifting;
            //if (Filter != null && !Filter.Contains(id.ToString()))
            //{
            //    return;
            //}
            //////if (id < 1 || id > MaxId)
            //////{
            //////    return;
            //////}

            Location location = GetLocation(antennaId);

            foreach (Tag tag in Tags)
            {
                if (tag.Id == id)
                {
                    if (tag.LastMovement.Location != location)
                    {
                        DateTime date = DateTime.Now;
                        double seconds = date.Subtract(tag.LastMovement.Date).TotalSeconds;

                        //if (seconds < TolaranceInSeconds)
                        //{
                        //    return;
                        //}

                        if (seconds < TolaranceInSeconds)
                        {
                            tag.LastMovement.SignalCount++;
                            return;
                        }

                        //if (tag.LastMovement.SignalCount + 1 < TolaranceSignalCount)
                        //{
                        //    tag.LastMovement.SignalCount++;
                        //    return;
                        //}

                        tag.LastMovement.Duration = Convert.ToInt32(seconds);


                        Movement movement = new Movement(location, date);
                        movement.Duration = -1;
                        tag.Movements.Add(movement);

                        if (TagLocationChanged != null)
                            TagLocationChanged(tag);
                    }

                    tag.LastMovement.SignalCount++;
                    if (TagRead != null)
                        TagRead(tag, rssi);
                    return;
                }
            }

            //if (!exists)

            Tag t = new Tag();
            t.Id = id;

            DateTime d = DateTime.Now;
            Movement m = new Movement(location, d);
            m.Duration = -1;
            m.SignalCount++;
            t.Movements.Add(m);

            Tags.Add(t);
            if (TagLocationChanged != null)
                TagLocationChanged(t);

            if (TagRead != null)
                TagRead(t, rssi);
        }



        public void Reset()
        {
            tags.Clear();
        }

        public DataTable GetMovementBasedReport()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Id", typeof(int));
            dt.Columns.Add("MovementDate", typeof(DateTime));
            dt.Columns.Add("Location", typeof(string));
            dt.Columns.Add("Duration", typeof(string));
            dt.Columns.Add("SignalCount", typeof(string));

            foreach (Tag tag in Tags)
            {
                foreach (Movement movement in tag.Movements)
                {
                    DataRow dr = dt.NewRow();
                    dr["Id"] = tag.Id;
                    dr["MovementDate"] = movement.Date;
                    dr["Location"] = movement.Location;
                    dr["Duration"] = movement.DurationInfo;
                    dr["SignalCount"] = movement.SignalCount;
                    dt.Rows.Add(dr);
                }
            }
            return dt;
        }

        public DataTable GetLocationBasedReport()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Id", typeof(int));
            dt.Columns.Add("Location", typeof(string));
            dt.Columns.Add("SignalCount", typeof(int));

            foreach (Tag tag in Tags)
            {
                int totalInside = 0;
                int totalOutside = 0;
                foreach (Movement movement in tag.Movements)
                {
                    if (movement.Location == Location.Inside)
                        totalInside += movement.SignalCount;
                    else
                        totalOutside += movement.SignalCount;
                }

                DataRow dr = dt.NewRow();
                dr[0] = tag.Id;
                dr[1] = Location.Inside;
                dr[2] = totalInside;
                dt.Rows.Add(dr);

                dr = dt.NewRow();
                dr[0] = tag.Id;
                dr[1] = Location.Outside;
                dr[2] = totalOutside;
                dt.Rows.Add(dr);
            }
            return dt;
        }

        public double TolaranceInSeconds { get; set; }

        public void Close()
        {
            dm.StopReader();
        }

        public System.Windows.Forms.Form BoundForm
        {
            set
            {
                value.FormClosing += new System.Windows.Forms.FormClosingEventHandler(value_FormClosing);
            }
        }

        void value_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            Close();
        }

        public string Filter
        {
            get;
            set;
        }

        public int IdShifting { get; set; }

        public int MaxId { get; set; }

        //public int TolaranceSignalCount { get; set; }
    }
}